react函数式组件和类组件创建ref的方法
类组件创建ref
父组件
1 | // 引入React |
子组件
1 | // 引入React |
函数式组件创建ref
1 | import React, { useRef, useImperativeHandle } from 'react'; |
父组件
1 | // 引入React |
子组件
1 | // 引入React |
1 | import React, { useRef, useImperativeHandle } from 'react'; |
解释执行:输入代码——解析器——中间代码——解释器——输出结果
编译执行:输入代码——解析器——中间代码——编译器——机器代码——输出结果
优缺点:解释执行的启动速度快,但是执行时的速度慢,而编译执行的启动速度慢,但是执行时的速度快
v8采用了,解释执行与编译执行相结合混合编译执行的技术也就是JIT(Just In Time)
初始化执行环境:事件循环系统,全局作用域,全局执行上下文,堆和栈,消息循环系统
输入一行代码
解析器解析:v8会结构化这段字符串,生成抽象语发树(AST)和相关作用域
中间代码字节码:字节码是介于AST与机器代码的中间代码,字节码可以被解释器直接执行,或者编译器编译成二进制机器代码执行。
解释器:监听器判断是不是热点代码(代码多次被执行),如不是直接有解释器输出结构(这一步也就是解释执行的实际应用)
编译器(编译热点代码)优化:将热点代码编译成机器码,这样下次执行是就可以忽略前面过程直接输出结果,这是编译执行的过程。
编译器反优化:如果对象的结构和属性发生改变,那么v8就会调用反优化,将二级制代码回退到优化之前,下次执行就会回退到解释器执行了。
name:的默认值是anonymous,他表示函数对象没有被设置名称;
b:表示函数代码,以字符串存储在内存中,当函数执行时,v8会从函数中抽离出code属性值,解释执行这段代码
如果某个编程语言的函数,可以和这个语言的数据类型做一样的事情,我们就把和这个语言中的函数称为一等公民
常规属性:字符串属性根据创建时的顺序升序排列,字符串属性就被称为常规属性,在V8中被称为properties
排序属性:在EMAScript规范中定义了数字属性应该按照索引值大小升序排列,在这里我们把对象中的数字属性称为排序属性
v8会给对象增加2个隐藏属性,elements(存放排序属性),properties(按照创建时的顺序保存了常规属性),把对象处理成2种线性数据结构
2.对象内属性:properties存储了常规属性,这样简化了复杂度,但是却多了一步操作,查找B时需要先找properties,再找B,这样影响效率,于是v8采用了权衡的策略以加快查找属性的的效率,把部分属性存储到对象本身,这种叫做对象内属性(in-object properties),默认最多为10个,超过放到properties上
3.快属性与慢属性
快属性:只需要通过索引即可访问的属性叫做快属性。访问速度快,但是大量删除或添加属性时,执行速度非常低,耗费大量时间和内存。
慢属性:对象的属性过多时,V8就会采取另外一种存储策略,那就是“慢属性”策略。慢属性的对象内部会有独立的非线性数据结构(词典)作为属性存储容器。
为了提升查找效率,v8在对象中添加了2个隐藏属性,排序属性和常规属性;element指向element对象(按照顺序存放排序属性),properties指向properties对象(按照创建顺序存放常规属性)
何谓惰性解析:解析器在解析的过程中,如遇到函数声明,name会跳过函数内部的代码,并不会为其生成AST码和字节码,而仅仅生成顶层代码的AST码和字节码。可以加快代码解析速度,极大地减少用户等待时间
惰性解析短板:虽然采取了惰性解析,但是仅仅解析顶层代码,如果函数内部还有函数那样就会一起销毁了,显然是不对的。于是谷歌采用了预解析器,他会对函数内部做一次快速地预解析,一是为了判断当前函数是不是存在语法上的错误,二是检查函数内部是不是引用了外部变量,如引用,v8会将栈变量复制到堆中,下次直接调用堆中的
代际假说(The Generational Hypothesis)的两大特点
大部分对象都是朝生暮死,比如函数内部变量,块级作用域中的变量等,代码执行完以后就会销毁,这类对象分配的内存很快就会变得不可访问。
第二个是不死的对象,会活得更久,比如全局的window、DOM、Web API等对象。
小的对象会被分配到新生代
这个区域比较小,新生代垃圾回收频繁,需要将活的对象复制到空闲区域,提高执行效率,所以分配了小的空间。
新生代区域分为:对象区和空闲区。数据最开始存储在对象区
新生代垃圾回收步骤:内存满了触发垃圾回收——>可访问性(reachability算法进行标记——>将存活的对象复制到空闲区(有序的排列)——>对象区清空——>然后空闲区与对象区翻转——>完成新生代垃圾回收
对象晋升策略:副垃圾回收器还会采用对象晋升策略,也就是移动那些经过两次垃圾回收依然还存活的对象到老生代中。
大的对象,新生代经过两次垃圾回收依然存在的对象
步骤:标记——>标记-清除算法——>标记-整理算法——>完成
标记阶段:从一组根元素开始,遍历递归这组元素,能访问的元素成为活动对象,否则就是垃圾数据
清除阶段:他与副垃圾回收器不一样,他仅仅将垃圾数据清楚,并未对内存碎片进行整理。这也就导致了碎片过多,无法分配足够的连续内存
整理阶段:先标记回收对象,让所有存活对象向一端移动,并清理掉这一端之外的内存
JavaScript是执行再主线程上的(单线程),垃圾回收一旦执行就会阻塞js,带到垃圾回收完毕,再恢复js进程,我们把这种行为叫做全停顿(Stop-The-World)
如果回收过程超过200毫秒用户就会觉得页面卡顿,于是:
将一个完整的垃圾回收任务拆分成多个小的任务(解决长任务)
将标记对象,移动对象等任务转移到后台线程进行(减少主线程暂停时间)
在执行一个完整的垃圾回收过程中,垃圾回收器会使用多个辅助线程来并行执行垃圾回收。
垃圾回收所消耗的时间,等于总体辅助线程所消耗的时间(辅助线程数量乘以单个线程所消耗的时间),再加上一些同步开销的时间。
仍然是一种全停顿的垃圾回收方式
增量标记的算法,比全停顿的算法要稍微复杂,这主要是因为增量回收是并发的(concurrent),要实现增量执行,需要满足两点要求:
垃圾回收可以被随时暂停和重启,暂停时需要保存当时的扫描结果,等下一波垃圾回收来了之后,才能继续启动。
在暂停期间,被标记好的垃圾数据如果被JavaScript代码修改了,那么垃圾回收器需要能够正确地处理。
三色标记法和写屏障机制可以很好地实现增量垃圾回收。
并发回收的优势非常明显,主线程不会被挂起,JavaScript 可以自由地执行 ,在执行的同时,辅助线程可以执行垃圾回收操作。
首先主垃圾回收器主要使用并发标记,我们可以看到,在主线程执行JavaScript,辅助线程就开始执行标记操作了,所以说标记是在辅助线程中完成的
标记完成之后,再执行并行清理操作。主线程在执行清理操作时,多个辅助线程也在执行清理操作。
另外,主垃圾回收器还采用了增量标记的方式,清理的任务会穿插在各种JavaScript任务之间执行。
1 | Cant perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method” |
1 |
|
####安装
npm install qrcode.react –save
import QRCode from ‘qrcode.react’;
1 | React.render( |
| prop | type | default value |
|---|---|---|
| value | string | |
| renderAs | string (‘canvas’ ‘svg’) | ‘canvas’ |
| size | number | 128 |
| bgColor | string (css color) | “#FFFFFF” |
| fgColor | string (css color) | “#000000” |
| level | string (‘L’ ‘M’ ‘Q’ ‘H’) | ‘L’ |
| includeMargin | boolean | false |
1 |
|
1 | //传入为空返回成成功态,所有加载完才会,改成功态,一个失败态就会直接结束 |
1 | Promise.ra_ce = function(promises) { |
不管成功还是失败,都会走到finally中,并且finally之后,还可以继续then。并且会将值原封不动的传递给后面的then。
1 | Promise.prototype.finally_ = function (callback) { |
代替div作为外层,可做不可见的包裹元素
增加了许多没必要的嵌套,增加了浏览器的渲染压力1 |
|
1 | import React from 'react'; |
props 和 state 进行浅层比较,并减少了跳过必要更新的可能性。shouldComponentUpdate(),而 React.PureComponent中以浅层对比 prop 和 state 的方式来实现了该函数。1 | import React, { Component } from 'react'; |
##面试—provide与inject用法
不存在双向绑定,用inject注入的
以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。
1 | //祖宗注入。provide |
1 | //后代通过inject都可以拿到 |
session 是什么?
session:服务端技术,意为会话控制;
和 cookie 不同,session 是保存在服务器上的,而且并不会随着 http 传递;因为 cookie 保存在客户端,
还是很不安全的,服务器为了杜绝这种事情,在服务器上也搞了一个存储用户信息的东西,这就是 session。
一般用于用户的登录状态,用户 id 等敏感信息的保存;
session 怎么使用?
以登录为例,当我们登录后,服务端会在 cookie 中设置当前用户的登录状态为已经登录,
同时在服务器上生成一份 session 文件,session 中存储用户 id,登录状态的有效期限等;这个 session 文件有
一个 id,生成 session 文件后,服务器还会把 session-id 写进 cookie。然后返回给客户端,此时用户的客户端
收到的 cookie 中包含登录状态和 session-id;等下一次再去请求时,http 协议会自动带着所有的 cookie
去请求;等服务器收到请求后,从 cookie 中把用户信息拿出来,然后再根据 session-id 把 session 读取出来,
再从 session 中查询登录状态,如果登录状态有效,就继续正常的响应,否则就返回登录失效的状态,要求用户登录;
token 原理?
一般在用户登录时,客户端把用户的用户名和密码传递给服务器,服务端进行校验,如果没有问题,就会生成一个
token;token 是一个字符串,这个字符串一般是加密过的,一般包含了用户 id,登录的时间戳,以及 sign
(签名,生成 token 的前几位进行加密的结果,可以防止 token 被篡改,一旦篡改了后面这一段和前面的对不上了)
;生成 token 后,服务器把 token 返回给前端,然后前端下次请求的时候需要带上这个 token,然后服务端在接收
到请求后会首先校验这个 token 是否有效,如果有效继续受理请求,如果无效则直接拒绝;
使用 token 的方式有哪些?
1.服务端也可以直接把 token 写进 cookie 中,下次客户端发起请求时会自动带上;
2.服务端也可以作为数据返给前端,但是前端此时需要手动的保存这个 token,可以保存在 localStorage 中,下次发请求时从 ls 中取出作为参数传给服务器即可
3.服务端返回 token 后,客户端可以把这个 token 写进请求头中,然后服务端每次从请求头中获取;
session 和 cookie 的区别?
session 存在服务器上,是服务器的技术;
cookie 存在客户端,是 http 协议的一部分;